package com.lin.sys.service.impls;



import org.apache.dubbo.config.annotation.Service;
import service.IdWorker;
import util.Const;

@Service
public class UserIdWorker implements IdWorker {

    private final static long firstTimestamp = Const.FIRST_TIMESTAMP;
    private final static long workerIdBits = Const.WORKERID_BITS;
    private final static long typeBigs = Const.TYPE_BIGS;
    private final static long sequenceBits = Const.SEQUENCE_BITS;

    private final static long maxWorkerId = -1L ^ -1L << workerIdBits;
    private final static long maxTypeId = -1L ^ -1L << typeBigs;

    private final static long typeIdShift = sequenceBits;
    private final static long workerIdShift = typeIdShift + typeBigs;
    private final static long timestampShift = workerIdShift + workerIdBits;
    private final static long sequenceMask = -1L ^ -1L << sequenceBits;

    private  long workerId;
    private long typeId;

    private long sequence = 0L;
    private long lastTimestamp = -1L;

//    public UserIdWorker(final long workerId, final long typeId) {
//        if (workerId > maxWorkerId || workerId < 0) {
//            throw new IllegalArgumentException(String.format("Worker Id can't be greater than %d or less than 0", maxWorkerId));
//        }
//        if (typeId > maxTypeId || typeId < 0) {
//            throw new IllegalArgumentException(String.format("Type Id can't be greater than %d or less than 0", maxTypeId));
//        }
//
//        this.workerId = workerId;
//        this.typeId = typeId;
//
//    }

    public synchronized long nextId() {
        long timestamp = this.timeGen();
        if (this.lastTimestamp == timestamp) {
            this.sequence = (this.sequence + 1) & sequenceMask;
            if (this.sequence == 0) {
                timestamp = this.tilNextMillis(this.lastTimestamp);
            }
        } else {
            this.sequence = 0;
        }

        if (timestamp < this.lastTimestamp) {
            throw new IllegalStateException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", this.lastTimestamp - timestamp));
        }

        this.lastTimestamp = timestamp;
        long nextId = ((timestamp - firstTimestamp << timestampShift)) | (this.workerId << workerIdShift) | (this.typeId << typeIdShift) | (this.sequence);
        return nextId;
    }

    private long tilNextMillis(final long lastTimestamp) {
        long timestamp = this.timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = this.timeGen();
        }
        return timestamp;
    }

    private long timeGen() {
        return System.currentTimeMillis();
    }

}
